<section>
<p><b>ForeignKey</b></p>
<p><code>class ForeignKey(othermodel, on_delete, **options)</code><a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/fields/related/#ForeignKey">[source]</a></p>
<p>该字段用于定义多对一关系。有一个必填的位置参数：与该模型关联的类(Model)。</p>
<p>Django允许创建一个递归的关联 —— 一个指向自己(Model)的多对一关系 —— 请使用models.ForeignKey('self')。</p>
<p>Django也允许与一个还没有定义的Model建立多对一的关系, 只需要在定义关联关系的时候使用其Model的名字，就像这样</p>
<pre>
from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass
</pre>
<p>采用上面这种方式在抽象类上面定义的关系字段要在其子类里面才会解析。例如</p>
<pre>
products/models.py
from django.db import models

class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)  # 不揭西

    class Meta:
        abstract = True
</pre>
<pre>
production/models.py
from django.db import models
from products.models import AbstractCar

class Manufacturer(models.Model):
    pass

class Car(AbstractCar):
    pass

# Car.manufacturer 会被解析为一个指向 production.Manufacture的多对一关系(Foreign Key)
</pre>
<p>使用类名的方式定义关联关系也能够允许跨app定义关系。只需要在类名前面加上app的标签。例如</p>
<pre>
class Car(models.Model):
    manufacturer = models.ForeignKey(
        'production.Manufacturer',
        on_delete=models.CASCADE,
    )
</pre>
<p>Django会为ForeignKey类型的字段默认创建一个数据库索引，可以通过设置db_index为False的方式来取消这一默认行为。</p>
<p><b>数据库表示</b></p>
<p>默认情况下，ForeignKey类型的字段对应的数据库的列名为field名字的小写形式后面附加"_id", 例如上例中的manufacturer在数据库的列名为manufacturer_id。Django推荐使用这一默认形式</p>
<p><b>参数</b></p>
<p><b>ForeignKey.on_delete</b></p>
<p>此参数控制的是当ForeignKey关联的对象被删除后Django的行为。它模拟了SQL中on_delete这一约束的行为。例:</p>
<pre>
user = models.ForeignKey(
    User,
    models.SET_NULL,  # 关联对象被删除后将该字段设为NULL
    blank=True,
    null=True,
)
</pre>
<p>on_delete参数的可选值在django.db.models模块定义，如下:</p>
<p>CASCADE<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#CASCADE">[source]</a></p>
<p>级联删除。on_delete设为这个值时，删除ForeignKey的关联对象的同时也会删除拥有ForeignKey的对象</p>
<p>PROTECT<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#PROTECT">[source]</a></p>
<p>禁止删除ForeignKey关联的对象</p>
<p>SET_NULL<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#SET_NULL">[source]</a></p>
<p>删除关联对象后把该字段设为NULL，只在null=True的时候使用</p>
<p>SET_DEFAULT<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#SET_DEFAULT">[source]</a></p>
<p>删除关联对象后把该字段设为默认值(default属性指定的值，或者本来的默认值)</p>
<p>SET()<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#SET">[source]</a></p>
<p>设为SET()的参数，传给SET()的参数可以是值类型的也可以是callable(可调用类型，较常用，可以避免在import model时进行数据库查询)。例:</p>
<pre>
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models

def get_sentinel_user():
    return get_user_model().objects.get_or_create(username='deleted')[0]

class MyModel(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET(get_sentinel_user),
    )
</pre>
<p>DO_NOTHING<a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/deletion/#DO_NOTHING">[source]</a></p>
<p>什么事情都不做。在某些有一致性检查的数据库会报错。</p>
<p><b>ForeignKey.limit_choices_to</b></p>
<p>使用ModelForm时限定该字段可选的值。例</p>
<pre>
staff_member = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    limit_choices_to={'is_staff': True},  # form的选择框里只会显示is_staff是True的值
)
</pre>
<p><b>ForeignKey.related_name</b></p>
<p>指定从ForeignKey关联的对象查询拥有ForeignKey的对象时所使用的属性的名字，也是related_query_name的默认值。该值默认为modelname_set的形式(把modelname替换成Model名的小写形式)。如果该属性的值包含有'+', 那么Django不会创建反向的关联关系。例:</p>
<pre>
class MyModel(models.Model)
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='+',  # 只能从MyModel查询User，不能从User查询MyModel
    )
</pre>
<p>ForeignKey.related_query_name</p>
<p>反向过滤属性使用的名字，其默认值为related_name或default_related_name这两个参数的值，如果这两个参数都没有值那么直接用Model的名字。例:</p>
<pre>
# Declare the ForeignKey with related_query_name
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")  # 反向的过滤查询
</pre>
<p>related_name和related_query_name这两个概念不太好区分。下面来讲解以下区别。</p>
<pre>
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# That's now the name of the reverse filter
article = Article.objects.get(pk=1)
Article.objects.filter(tag__name="important")
</pre>
<p>在上面的实例代码中，我们在Tag中定义了一个关联到Article的ForeignKey。那么related_name就是article.tag_set, 而related_query_name是指<code>Article.objects.filter(tag__name="important")</code>中的'tag'</p>

<p>ForeignKey.to_field</p>
<p>该属性指定使用目标Model的哪一个字段来构建ForeignKey关系。默认情况下使用id(主键)。需要确保目标Model的该字段是唯一的(设置unique=True)。</p>
<p>ForeignKey.db_constraint</p>
<p>该属性控制是否在数据库中为该ForeignKey创建约束(constraint), 默认为True，推荐使用True，设为False不利于保持数据一致性或者完整性(integrity)</p>
<p>ForeignKey.swappable</p>
<p>该属性默认为True，django也推荐日常使用True。</p>
<p>关于这个属性的实际意义(什么样的Model算是swappable)，本人在django文档中没有找到，请知道的大神邮件告知。</p>
</section>
<section>
<p><b>ManyToManyField</b></p>
<p><code>class ManyToManyField(othermodel, **options)</code><a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/fields/related/#ManyToManyField">[source]</a></p>
<p>该字段类型用于定义多对多关系。该类型有个必填的参数用来指定与哪个Model建立多对多关系(同ForeignKey一样的)。关联对象可以通过该字段的RelatedManager来进行添加，删除，创建等。</p>
<p>数据库表示</p>
<p>默认情况下，Django会建立一个中间表来存储多对多的关联关系。默认的表名由ManyToManyField的名字以及包含ManyToManyField字段的Model的名字组合而来。</p>
<p>参数:</p>
<p>ManyToManyField.related_name, 参考ForeignKey</p>
<p>ManyToManyField.related_query_name， 参考ForeignKey</p>
<p>ManyToManyField.limit_choices_to， 参考ForeignKey，注意:设置了through参数后，该参数失效</p>
<p>ManyToManyField.symmetrical</p>
<p>只用于与自身进行关联的ManyToManyField(指向自己的多对多关系)。例:</p>
<pre>
from django.db import models

class Person(models.Model):
    friends = models.ManyToManyField("self")
</pre>
<p>上面的代码定义了一个指向Person自己的多对多关系。对于这种情况，Django默认就不会再创建一个person_set属性(用于反向关系)。这种多对多关系在Django中称为对称的多对多关系(symmetrical), 比如，你是我的朋友，我也是你的朋友</p>
<p>如果我们不想要这种对称性，那么就把symmetrical参数设成False，这时Django会创建person_set这个属性</p>
<p>ManyToManyField.through</p>
<p>用来指定一个充当中间类角色的Model，Django通过该中间Model来管理该多对多关系。通常在想要给这个多对多关系附加一些额外的信息时才会用到。可以参考本教程的Model那一章，也可以看<a href="https://docs.djangoproject.com/en/1.10/topics/db/models/#intermediary-manytomany">这里</a></p>
<p>不给这个参数传值时，Django会给该参数设置一个默认值。这个默认的中间Model有3个字段，对于不同Model之间的多对多关系，这3个字段分别是</p>
<ul>
    <li>id: 代表这个多对多关系的主键</li>
    <li><span><</span>containing_model<span>></span>_id: 代表定义了该多对多关系的Model的实例对象的id</li>
    <li><span><</span>other_model<span>></span>_id: 代表这一多对多关系关联的Model的实例对象的id</li>
</ul>
<p>指向自身的多对多关系的中间Model的3个字段为</p>
<ul>
    <li>id: 代表这个多对多关系的主键</li>
    <li>from_<span><</span>model<span>></span>_id: 充当源Model角色的对象的id</li>
    <li>to_<span><</span>model<span>></span>_id: 充当目标Model角色的对象的id</li>
</ul>
<p>ManyToManyField.through_fields</p>
<p>这个参数只在through参数也设置的情况下使用。through_fields这个参数指定了使用中间Model的那几个字段来管理多对多关系。例:</p>
<pre>
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(
        Person,
        through='Membership',
        through_fields=('group', 'person'),
    )

class Membership(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    inviter = models.ForeignKey(
        Person,
        on_delete=models.CASCADE,
        related_name="membership_invites",
    )
    invite_reason = models.CharField(max_length=64)
</pre>
<p>上面这个例子中，Membership有2个指向Person的ForeignKey，Django自己没有办法判断哪一个应该用于这个多对多关系，通过在Group里面指定through_fields就告诉Django，使用Membership的group和person这两个字段来管理多对多关系</p>
<p>through_fields这个参数的值为一个二元的tuple(列表也行)，第一个元素中间Model(Membership)中指向多对多关系的源Model的字段的名字(group)，第二个元素为中间Model指向目标Model的ForeignKey的字段的名字(person)，顺序不能调换</p>
<p>使用中间Model的指向自身的多对多关系，Django会强制设置symmetrical=False</p>
<p>ManyToManyField.db_table</p>
<p>指定中间表的表名，默认是由定义ManyToManyField的Model名和ManyToManyField的字段名组合而来</p>
<p>ManyToManyField.db_constraint</p>
<p>控制是否要为中间Model的ForeignKey字段在数据库中创建约束。默认为True，推荐使用默认的。注意: db_constraint和through不能同时使用</p>
<p>ManyToManyField.swappable</p>
<p>同ForeignKey</p>
</section>
<section>
<p><b>OneToOneField</b></p>
<p><code>class OneToOneField(othermodel, on_delete, parent_link=False, **options)</code><a href="https://docs.djangoproject.com/en/1.10/_modules/django/db/models/fields/related/#OneToOneField">[source]</a></p>
<p>该字段用于定义一对一的关联关系, 第一个位置参数为必填参数，它指定了与哪个Model建立一对一的关联关系。OneToOneField的related_name参数默认情况下为Model名的小写，而不是xxx_set。例:</p>
<pre>
from django.conf import settings
from django.db import models

class MySpecialUser(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    supervisor = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='supervisor_of',
    )
</pre>
<pre>
>>> user = User.objects.get(pk=1)
>>> hasattr(user, 'myspecialuser')  # 默认
True
>>> hasattr(user, 'supervisor_of')
True
</pre>
<p>OneToOneField的参数跟ForeignKey相同，在ForeignKey参数的基础上加了一个parent_link</p>
<p>OneToOneField.parent_link</p>
<p>这是一个布尔类型的字段，用于控制Model继承中，是否要添加默认的指向父类Model的OnetoOneField。</p>
</section>